package tcp

import (
	"context"
	"gitee.com/lipore/go-nio/pkg/transport"
	"net"
	"net/url"
)

type tcpFactory struct {
	idFactory transport.ChannelIDFactory
}

func NewTcpFactory(idFactory transport.ChannelIDFactory) transport.Factory {
	return &tcpFactory{idFactory: idFactory}
}

func (t tcpFactory) Schemes() transport.Schemes {
	return transport.Schemes{"tcp", "tcp4", "tcp6"}
}

func (t tcpFactory) Listen(address *url.URL) (transport.Acceptor, error) {
	if err := t.Schemes().FixURL(address); nil != err {
		return nil, err
	}

	l, err := net.Listen(address.Scheme, address.Host)
	if nil != err {
		return nil, err
	}

	//TODO pass options
	return NewTcpAcceptor(l.(*net.TCPListener), t.idFactory), nil
}

type tcpAcceptor struct {
	listener  *net.TCPListener
	ctx       context.Context
	done      chan struct{}
	idFactory transport.ChannelIDFactory
}

func NewTcpAcceptor(listener *net.TCPListener, idGenerator func() int64) transport.Acceptor {
	return &tcpAcceptor{
		idFactory: idGenerator,
		listener:  listener,
		done:      make(chan struct{}),
	}
}

func (t *tcpAcceptor) Accept() (transport.Transport, error) {
	conn, err := t.listener.Accept()
	if err != nil {
		return nil, err
	}
	tt := newTcpTransport(t.idFactory(), conn.(*net.TCPConn))
	return tt, err
}

func (t *tcpAcceptor) Close() error {
	close(t.done)
	return t.listener.Close()
}
